package com.ljh.onlinetest.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ljh.onlinetest.domain.*;
import com.ljh.onlinetest.domain.enums.ExamPaperAnswerStatusEnum;
import com.ljh.onlinetest.domain.enums.ExamPaperTypeEnum;
import com.ljh.onlinetest.domain.enums.QuestionTypeEnum;
import com.ljh.onlinetest.domain.exam.ExamPaperTitleItemObject;
import com.ljh.onlinetest.domain.other.ExamPaperAnswerUpdate;
import com.ljh.onlinetest.domain.task.TaskItemAnswerObject;
import com.ljh.onlinetest.domain.task.TaskItemObject;
import com.ljh.onlinetest.repository.*;
import com.ljh.onlinetest.service.ExamPaperAnswerService;
import com.ljh.onlinetest.service.ExamPaperQuestionCustomerAnswerService;
import com.ljh.onlinetest.service.TaskExamCustomerAnswerService;
import com.ljh.onlinetest.service.TextContentService;
import com.ljh.onlinetest.utils.ExamUtil;
import com.ljh.onlinetest.utils.JsonUtil;
import com.ljh.onlinetest.viewmodel.admin.paper.ExamPaperAnswerPageRequestVM;
import com.ljh.onlinetest.viewmodel.student.exam.ExamPaperSubmitItemVM;
import com.ljh.onlinetest.viewmodel.student.exam.ExamPaperSubmitVM;
import com.ljh.onlinetest.viewmodel.student.exampaper.ExamPaperAnswerPageVM;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author ljh
 * @ClassName ExamPaperAnswerServiceImpl.java
 * @createTime 2022年02月22日
 */
@Service
public class ExamPaperAnswerServiceImpl extends BaseServiceImpl<ExamPaperAnswer> implements ExamPaperAnswerService {
    private ExamPaperAnswerMapper examPaperAnswerMapper;
    private ExamPaperMapper examPaperMapper;
    private TextContentService textContentService;
    private QuestionMapper questionMapper;
    private ExamPaperQuestionCustomerAnswerService customerAnswerService;
    private TaskExamCustomerAnswerMapper taskExamCustomerAnswerMapper;

    @Autowired
    public ExamPaperAnswerServiceImpl(ExamPaperAnswerMapper examPaperAnswerMapper,ExamPaperMapper examPaperMapper,TextContentService textContentService,QuestionMapper questionMapper,ExamPaperQuestionCustomerAnswerService customerAnswerService,TaskExamCustomerAnswerMapper taskExamCustomerAnswerMapper) {
        super(examPaperAnswerMapper);
        this.examPaperAnswerMapper = examPaperAnswerMapper;
        this.examPaperMapper = examPaperMapper;
        this.textContentService = textContentService;
        this.questionMapper = questionMapper;
        this.customerAnswerService = customerAnswerService;
        this.taskExamCustomerAnswerMapper = taskExamCustomerAnswerMapper;
    }

    @Override
    public PageInfo<ExamPaperAnswer> page(ExamPaperAnswerPageRequestVM model) {
        return PageHelper.startPage(model.getPageIndex(), model.getPageSize(),"id desc").doSelectPageInfo(() ->
                examPaperAnswerMapper.adminPage(model)
        );
    }

    @Override
    public Integer selectAllCount() {
        return examPaperAnswerMapper.selectAllCount();
    }

    @Override
    public ExamPaperAnswerInfo calculateExamPaperAnswer(ExamPaperSubmitVM examPaperSubmitVM, User user) {
        ExamPaperAnswerInfo paperAnswerInfo = new ExamPaperAnswerInfo();
        Date now = new Date();
        ExamPaper examPaper = examPaperMapper.selectByPrimaryKey(examPaperSubmitVM.getId());
        ExamPaperTypeEnum examPaperTypeEnum = ExamPaperTypeEnum.fromCode(examPaper.getPaperType());
        //任务试卷只能做一次
        if (examPaperTypeEnum == ExamPaperTypeEnum.Task){
            ExamPaperAnswer examPaperAnswer = examPaperAnswerMapper.getByPidUid(examPaperSubmitVM.getId(),user.getId());
            if (null != examPaperAnswer)
                return null;
        }
        //获取任务试卷内容
        String content = textContentService.selectById(examPaper.getFrameTextContentId()).getContent();
        //转化成Json对象
        List<ExamPaperTitleItemObject> paperTitleItemObjects = JsonUtil.toJsonListObject(content, ExamPaperTitleItemObject.class);
        //从Json对象中获取到试卷题目的id集合
        List<Integer> questionIds = paperTitleItemObjects.stream().flatMap(item -> item.getQuestionItems().stream().map(q -> q.getId())).collect(Collectors.toList());
        //根据题目的Id集合查询所有的题目
        List<Question> questions = questionMapper.selectByIds(questionIds);
        //将题目结构转化为题目答案
        List<ExamPaperQuestionCustomerAnswer> customerAnswers = paperTitleItemObjects.stream().flatMap(t -> t.getQuestionItems().stream().map(questionItemObject -> {
            Question question = questions.stream().filter(tq -> tq.getId().equals(questionItemObject.getId())).findFirst().get();
            ExamPaperSubmitItemVM customerQuestionAnswer = examPaperSubmitVM.getAnswerItems().stream()
                    .filter(tq -> tq.getQuestionId().equals(questionItemObject.getId()))
                    .findFirst()
                    .orElse(null);
            return examPaperQuestionCustomerAnswerFromVM(question, customerQuestionAnswer, examPaper, questionItemObject.getItemOrder(), user, now);
        })).collect(Collectors.toList());
        ExamPaperAnswer examPaperAnswer = examPaperAnswerFromVM(examPaperSubmitVM,examPaper,customerAnswers,user,now);
        paperAnswerInfo.setExamPaper(examPaper);
        paperAnswerInfo.setExamPaperAnswer(examPaperAnswer);
        paperAnswerInfo.setExamPaperQuestionCustomerAnswers(customerAnswers);
        return paperAnswerInfo;
    }

    @Override
    public ExamPaperSubmitVM examPaperAnswerToVM(Integer id) {
        ExamPaperSubmitVM answer = new ExamPaperSubmitVM();
        ExamPaperAnswer examPaperAnswer = examPaperAnswerMapper.selectByPrimaryKey(id);
        answer.setId(examPaperAnswer.getId());
        answer.setDoTime(examPaperAnswer.getDoTime());
        answer.setScore(ExamUtil.scoreToVM(examPaperAnswer.getPaperScore()));
        //一张试卷有多个不同题型的试卷答案，取出所有答案，再转成前端的viewModel
        List<ExamPaperQuestionCustomerAnswer> customerAnswers = customerAnswerService.selectListByPaperAnswerId(examPaperAnswer.getId());
        List<ExamPaperSubmitItemVM> examPaperSubmitItemVMS = customerAnswers.stream()
                .map(a -> customerAnswerService.examPaperQuestionCustomerAnswerToVM(a))
                .collect(Collectors.toList());
        answer.setAnswerItems(examPaperSubmitItemVMS);
        return answer;
    }

    @Override
    public PageInfo<ExamPaperAnswer> studentPage(ExamPaperAnswerPageVM model) {
        return PageHelper.startPage(model.getPageIndex(),model.getPageSize(),"id desc").doSelectPageInfo(() ->
                    examPaperAnswerMapper.studentPage(model)
                );
    }

    @Override
    @Transactional
    public String judge(ExamPaperSubmitVM examPaperSubmitVM) {
        ExamPaperAnswer examPaperAnswer = examPaperAnswerMapper.selectByPrimaryKey(examPaperSubmitVM.getId());
        List<ExamPaperSubmitItemVM> judgeItems = examPaperSubmitVM.getAnswerItems().stream().filter(d -> d.getDoRight() == null).collect(Collectors.toList());
        List<ExamPaperAnswerUpdate> examPaperAnswerUpdates = new ArrayList<>(judgeItems.size());
        Integer userScore = examPaperAnswer.getUserScore();
        Integer questionCorrect = examPaperAnswer.getQuestionCorrect();
        for (ExamPaperSubmitItemVM judgeItem : judgeItems) {
            ExamPaperAnswerUpdate examPaperAnswerUpdate = new ExamPaperAnswerUpdate();
            examPaperAnswerUpdate.setId(judgeItem.getId());
            examPaperAnswerUpdate.setCustomerScore(ExamUtil.scoreFromVM(judgeItem.getScore()));
            boolean doRight = examPaperAnswerUpdate.getCustomerScore().equals(ExamUtil.scoreFromVM(judgeItem.getQuestionScore()));
            examPaperAnswerUpdate.setDoRight(doRight);
            examPaperAnswerUpdates.add(examPaperAnswerUpdate);
            userScore += examPaperAnswerUpdate.getCustomerScore();
            if (examPaperAnswerUpdate.getDoRight()){
                ++questionCorrect;
            }
        }
        examPaperAnswer.setUserScore(userScore);
        examPaperAnswer.setQuestionCorrect(questionCorrect);
        examPaperAnswer.setStatus(ExamPaperAnswerStatusEnum.Complete.getCode());
        examPaperAnswerMapper.updateByPrimaryKeySelective(examPaperAnswer);
        customerAnswerService.updateScore(examPaperAnswerUpdates);
        ExamPaperTypeEnum examPaperTypeEnum = ExamPaperTypeEnum.fromCode(examPaperAnswer.getPaperType());
        switch (examPaperTypeEnum){
            case Task:
                //任务试卷批改完成后，需要更新新任务的状态
                ExamPaper examPaper = examPaperMapper.selectByPrimaryKey(examPaperAnswer.getExamPaperId());
                Integer taskExamId = examPaper.getTaskExamId();
                Integer createUser = examPaperAnswer.getCreateUser();
                TaskExamCustomerAnswer taskExamCustomerAnswer = taskExamCustomerAnswerMapper.getByTUid(taskExamId,createUser);
                TextContent textContent = textContentService.selectById(taskExamCustomerAnswer.getTextContentId());
                List<TaskItemAnswerObject> taskItemAnswerObjects = JsonUtil.toJsonListObject(textContent.getContent(), TaskItemAnswerObject.class);
                taskItemAnswerObjects.stream()
                        .filter(d -> d.getExamPaperAnswerId().equals(examPaperAnswer.getId()))
                        .findFirst().ifPresent(taskItemAnswerObject -> taskItemAnswerObject.setStatus(examPaperAnswer.getStatus()));
                textContentService.jsonConvertUpdate(textContent,taskItemAnswerObjects,null);
                textContentService.updateByIdFilter(textContent);
                break;
            default:
                break;
        }
        return ExamUtil.scoreToVM(userScore);
    }

    private ExamPaperAnswer examPaperAnswerFromVM(ExamPaperSubmitVM examPaperSubmitVM, ExamPaper examPaper, List<ExamPaperQuestionCustomerAnswer> customerAnswers, User user, Date now) {
        int systemScore = customerAnswers.stream().mapToInt(a -> a.getCustomerScore()).sum();
        long count = customerAnswers.stream().filter(a -> a.getCustomerScore().equals(a.getQuestionScore())).count();
        ExamPaperAnswer examPaperAnswer = new ExamPaperAnswer();
        examPaperAnswer.setPaperName(examPaper.getName());
        examPaperAnswer.setDoTime(examPaperSubmitVM.getDoTime());
        examPaperAnswer.setExamPaperId(examPaper.getId());
        examPaperAnswer.setCreateUser(user.getId());
        examPaperAnswer.setCreateTime(now);
        examPaperAnswer.setSubjectId(examPaper.getSubjectId());
        examPaperAnswer.setQuestionCount(examPaper.getQuestionCount());
        examPaperAnswer.setPaperScore(examPaper.getScore());
        examPaperAnswer.setPaperType(examPaper.getPaperType());
        examPaperAnswer.setSystemScore(systemScore);
        examPaperAnswer.setUserScore(systemScore);
        examPaperAnswer.setTaskExamId(examPaper.getTaskExamId());
        examPaperAnswer.setQuestionCorrect((int) count);
        boolean needJudge = customerAnswers.stream().anyMatch(d -> QuestionTypeEnum.needSaveTextContent(d.getQuestionType()));
        if (needJudge){
            examPaperAnswer.setStatus(ExamPaperAnswerStatusEnum.WaitJudge.getCode());
        }else {
            examPaperAnswer.setStatus(ExamPaperAnswerStatusEnum.Complete.getCode());
        }
        return examPaperAnswer;

    }

    /**
     * 用户提交答案的转化存储对象
     * @param question
     * @param customerQuestionAnswer
     * @param examPaper
     * @param itemOrder
     * @param user
     * @param now
     * @return
     */
    private ExamPaperQuestionCustomerAnswer examPaperQuestionCustomerAnswerFromVM(Question question, ExamPaperSubmitItemVM customerQuestionAnswer, ExamPaper examPaper, Integer itemOrder, User user, Date now) {
        ExamPaperQuestionCustomerAnswer customerAnswer = new ExamPaperQuestionCustomerAnswer();
        customerAnswer.setQuestionId(question.getId());
        customerAnswer.setExamPaperId(examPaper.getId());
        customerAnswer.setQuestionScore(question.getScore());
        customerAnswer.setSubjectId(examPaper.getSubjectId());
        customerAnswer.setItemOrder(itemOrder);
        customerAnswer.setCreateTime(now);
        customerAnswer.setCreateUser(user.getId());
        customerAnswer.setQuestionType(question.getQuestionType());
        customerAnswer.setQuestionTextContentId(question.getInfoTextContentId());
        if (customerQuestionAnswer == null) {
            //用户没写答案，0分
            customerAnswer.setCustomerScore(0);
        }else{
            setSpecialFromVM(customerAnswer,question,customerQuestionAnswer);
        }
        return customerAnswer;
    }

    /**
     * 判断用户提交的答案是否正确，保留用户提交的答案
     * @param customerAnswer
     * @param question
     * @param customerQuestionAnswer
     */
    private void setSpecialFromVM(ExamPaperQuestionCustomerAnswer customerAnswer, Question question, ExamPaperSubmitItemVM customerQuestionAnswer) {
        QuestionTypeEnum questionType = QuestionTypeEnum.fromCode(customerAnswer.getQuestionType());
        switch (questionType){
            case SingleChoice:
            case TrueFalse:
                customerAnswer.setAnswer(customerQuestionAnswer.getContent());
                customerAnswer.setDoRight(question.getCorrect().equals(customerQuestionAnswer.getContent()));
                customerAnswer.setCustomerScore(customerAnswer.getDoRight()? question.getScore() : 0);
                break;
            case MultipleChoice:
                String customerChoice = ExamUtil.contentToString(customerQuestionAnswer.getContentArray());
                customerAnswer.setAnswer(customerChoice);
                customerAnswer.setDoRight(customerChoice.equals(question.getCorrect()));
                customerAnswer.setCustomerScore(customerAnswer.getDoRight()? question.getScore() : 0);
                break;
            case GapFilling:
                String userAnswer = customerQuestionAnswer.getContentArray().get(0);
                customerAnswer.setAnswer(userAnswer);
                String current = question.getCorrect();
                customerAnswer.setDoRight(current.equals(userAnswer));
                customerAnswer.setCustomerScore(customerAnswer.getDoRight()? question.getScore() : 0);
                break;
            default:
                customerAnswer.setAnswer(customerQuestionAnswer.getContent());
                customerAnswer.setCustomerScore(0);
                break;
        }
    }

}
